package com.xxrl.shop.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xxrl.shop.domain.Merchant;
import com.xxrl.shop.domain.Product;
import com.xxrl.shop.domain.ProductIndex;
import com.xxrl.shop.domain.User;
import com.xxrl.shop.repository.MerchantRepository;
import com.xxrl.shop.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;


/**
 * @author mis
 */
@Service
public class ProductService {

    private final ProductRepository productRepository;
    private final MerchantRepository merchantRepository;
    private final RecommendService recommendService;

    @Value("${my.spark.recommendSize}")
    private int recommendSize;

    private JSONArray hotProductJson;
    private final List<Product> defaultRecommendProductList;

    @Autowired
    public ProductService(ProductRepository productRepository, MerchantRepository merchantRepository, RecommendService recommendService) {
        this.productRepository = productRepository;
        this.merchantRepository = merchantRepository;
        this.recommendService = recommendService;
        defaultRecommendProductList = new ArrayList<>();
    }

    public int countProduct() {
        return (int) productRepository.count();
    }

    public int countVisit() {
        return (int) productRepository.countVisit();
    }


    public List<Product> productIndexToProductList(List<ProductIndex> productIndices) {
        List<Long> ids = new ArrayList<>();
        for (ProductIndex productIndex : productIndices) {
            ids.add(productIndex.getProductId());
        }
        return productRepository.findAllById(ids);
    }

    public List<Product> recommendForProduct(Long productId) {
        List<Long> product = recommendService.recommendForProduct(Math.toIntExact(productId), recommendSize);
        return productRepository.findAllById(product);
    }

    public List<Product> recommendForUser(Long userId) {
        List<Long> product = recommendService.recommendForUser(Math.toIntExact(userId), recommendSize);
        return productRepository.findAllById(product);
    }

    public List<Product> getProductByMainType(String mainType) {
        return  productRepository.queryProductsByMainType(mainType, PageRequest.of(0,6)).getContent();
    }

    public Product getProductById(Long id) {
        Product product = productRepository.getOne(id);
        product.setViewCount(product.getViewCount()+1);
        productRepository.save(product);
        return product;
    }

    /**
     * 自动获取最热商品并缓存
     */
    @Scheduled(cron = "0 0 0/2 * * ?")
    public void getHotProduct() {
        defaultRecommendProductList.clear();
        hotProductJson = new JSONArray(3);
        Sort sort = Sort.by(Sort.Direction.DESC, "viewCount");
        PageRequest pageRequest = PageRequest.of(0, recommendSize * 2, sort);
        List<Product> list = productRepository.findAll(pageRequest).toList();
        hotProductJson.addAll(list.subList(0, recommendSize));
        defaultRecommendProductList.addAll(list.subList(recommendSize, recommendSize * 2));
    }

    public JSONArray getHostProductList() {
        if (hotProductJson == null) {
            getHotProduct();
        }
        return hotProductJson;
    }

    /**
     * 根据标签获得tab
     * @param name 标签名
     * @return 包装好的tab
     */
    private JSONObject getProductsByType(String name) {
        JSONObject jsonObject = new JSONObject(3);
        JSONArray subArray = new JSONArray();
        List<Product> lists = getProductByMainType(name);
        subArray.addAll(lists);
        jsonObject.put("tabs",subArray);
        jsonObject.put("name",name);
        jsonObject.put("image","http://localhost:8080/images/tab.png");
        return jsonObject;
    }

    public JSONArray getHomePage(Long userId) {
        JSONArray jsonArray = new JSONArray();

        // 为你推荐
        JSONObject jsonObject = new JSONObject(3);
        JSONArray subArray = new JSONArray();
        List<Product> lists ;
        // using default recommend to fill lists upto recommendSize
        if (userId != null) {
            lists = recommendForUser(userId);
            if (lists.size() < recommendSize) {
                lists.addAll(defaultRecommendProductList.subList(0,recommendSize-lists.size()));
            }
        } else {
            lists = defaultRecommendProductList;
        }
        subArray.addAll(lists);
        jsonObject.put("tabs",subArray);
        jsonObject.put("name","为你推荐");
        jsonObject.put("image","http://localhost:8080/images/youmaylike.png");
        jsonArray.add(jsonObject);

        jsonArray.add(getProductsByType("日常用品"));
        jsonArray.add(getProductsByType("零食小吃"));
        return jsonArray;
    }

    @CacheEvict(cacheNames = "homePageStatistics")
    public void addProductByMerchant(Merchant merchant, Product product) {
        product.setMerchant(merchant);
        productRepository.save(product);
    }

    public Page<Product> findAllByUser(Long userId, Pageable pageable) {
        User user = new User(userId);
        return productRepository.queryProductsByMerchant(merchantRepository.queryByUser(user),pageable);
    }

    public Page<Product> findAll(Pageable pageable) {
        return productRepository.findAll(pageable);
    }

    public Page<Product> findAllPricesBetween(Pageable pageable, Integer gt, Integer let) {
        return productRepository.findAllByPricesBetween(pageable, gt, let);
    }

    @CacheEvict(cacheNames = "homePageStatistics")
    public void saveProduct(Product product) {
        assert product.getId() != null;
        productRepository.save(product);
    }

    public void removeProduct(Long id) {
        productRepository.deleteById(id);
    }
}
